<?php

namespace App\Services\Platform\Elasticsearch;

use App\Core\Traits\Numeral;
use App\Models\Game\Platform\Org;
use App\Services\Service;
use App\Services\Traits\DatabaseElasticsearch;
use App\Models\Elasticsearch\Settlement\Info as SettlementInfo;
use Helper\Timed;

class SettlementService extends Service
{
	use DatabaseElasticsearch, Numeral;

	/**
	 * 获取数据列表【天】
	 *
	 * @param \Illuminate\Http\Request $request
	 * @param bool $export
	 * @return \Illuminate\Database\Eloquent\Collection[]|int[]|array[]
	 */
	public function day($request, $export = false)
	{
		return $this->getList($request, '1d', $export);
	}

	/**
	 * 获取数据列表【月】
	 *
	 * @param \Illuminate\Http\Request $request
	 * @param bool $export
	 * @return \Illuminate\Database\Eloquent\Collection[]|int[]|array[]
	 */
	public function month($request, $export = false)
	{
		$datetime = $request->input('datetime');

		// date_default_timezone_set($request->user()->config->local_timezone);
		date_default_timezone_set(Timed::getJsLocalTimezoneNameByCookie());
		$end_time = strtotime(date('Y-m-01', strtotime('+1 month', $datetime[1])));
		if (!empty($datetime)) {
			$request->merge(['datetime' => [
				$datetime[0],
				$end_time - 1,
			]]);
		}

		return $this->getList($request, "1M", $export);
	}
	/**
	 * 获取游戏统计USD
	 *
	 * @param \Illuminate\Http\Request $request
	 * @param bool $export
	 * @return array[]|int[]|array[]
	 */
	public function getList($request, $groupBy, $export = false)
	{
		$params = ['body' => ['size' => 0]];

		// 筛选【状态】
		$this->makeWhere($params, 'status', SettlementInfo::STATUS_NORMAL);
		// 筛选【类型】
		$this->makeWhere($params, 'player_type', SettlementInfo::PLAYER_TYPE);
		// 筛选【平台】
		$this->makeWhereParamOrg($request, $params);
		// 筛选【平台】【排除】
		$this->makeWhereParamNot($request, 'plat_code_exclude', $params, 'plat_code');
		// 筛选【时间】
		$this->makeWhereParamDatetime($request, $params, 'end_time', 'datetime', SettlementInfo::INDEX_NAME);
		// 筛选【币种】
		$this->makeWhereParam($request, 'currency', $params);
		// 筛选【币种】【排除】
		$this->makeWhereParamNot($request, 'currency_exclude', $params, 'currency');

		// 列表数据
		$this->makeGroupDatetimeAggs($request, $params, 'sum', ['bet_num', 'gain_player', 'usd.bet_num', 'usd.gain_player'], ['currency', 'plat_code'], "group_str", $groupBy);

		//排序
		$order_column = $request->input('order_column', 'bet_base');
		$order = $request->input('order', 'asc');
		switch ($order_column){
			case "timed":
				$order_column = '_key';
				break;
			case "amount":
			case "revenue":
				$order_column = 'gain_player';
				$order = $order == 'asc' ? 'desc' : 'asc';
				break;
		}
		$this->makeAggsOrderParam($request, $params, $order_column, $order);

		$aggStat = SettlementInfo::search($params);
		// 数据条数
		$total = isset($aggStat['aggregations']) ? count($aggStat['aggregations']['group']['buckets']) : 0;

		//分页
		$this->makeAggsPaginationParam($request, $params);
		// 查询数据
		$results = SettlementInfo::search($params);
		if (isset($results['aggregations'])) {
			// 数据处理
			$stats= $this->makeStats($aggStat['aggregations'] ?? null, $request);
			$result= $this->getData($results['aggregations'] ?? null, $request);

			return [
				$result['data'],
				$total,
				$stats['stat'],
			];
		} else {
			return [
				[],
				0,
				[],
			];
		}
	}

	/**
	 * 获取游戏统计USD
	 * @param \Illuminate\Http\Request $request
	 * @param bool $export
	 * @return array[]|int[]|array[]
	 */
	public function getUsd($request, $export = false)
	{
		$params = ['body' => ['size' => 0]];

		// 筛选【状态】
		$this->makeWhere($params, 'status', SettlementInfo::STATUS_NORMAL);
		// 筛选【类型】
		$this->makeWhere($params, 'player_type', SettlementInfo::PLAYER_TYPE);
		// 筛选【平台】
		$this->makeWhereParamOrg($request, $params);
		// 筛选【平台】【排除】
		$this->makeWhereParamNot($request, 'plat_code_exclude', $params, 'plat_code');
		// 筛选【时间】
		$this->makeWhereParamDatetime($request, $params, 'end_time', 'datetime', SettlementInfo::INDEX_NAME);
		// 筛选【币种】
		$this->makeWhereParam($request, 'currency', $params);
		// 筛选【币种】【排除】
		$this->makeWhereParamNot($request, 'currency_exclude', $params, 'currency');

		// 统计数据

		$this->makeGroupAggs($request, $params, 'sum', ['bet_base', 'bet_num', 'gain_player', 'usd.bet_base', 'usd.bet_num', 'usd.gain_player'], ['plat_code'], '', 'datetime', '_');
		//排序
		$order_column = $request->input('order_column', 'bet_base');
		$order = $request->input('order');
		switch ($order_column){
			case "player_count":
				$order_column = 'distinct_uid';
				break;
			case "doc_count":
				$order_column = '_count';
				break;
			case "bet_base":
				$order_column = 'usd_bet_base';
				break;
			case "bet_num":
				$order_column = 'usd_bet_num';
				break;
			case "revenue":
			case "gain_player":
			case "amount":
				$order_column = 'usd_gain_player';
				$order = $order == 'asc' ? 'desc' : 'asc';
				break;
		}

		$this->makeAggsOrderParam($request, $params, $order_column, $order);

		// 查询数据
		$results = SettlementInfo::search($params);

		// 统计数据
		$stats = $this->makeStatsUsd($results['aggregations'] ?? null);

		return [
			$stats['data'],
			$stats['usd'],
		];
	}

	private function makeStatsUsd($aggs)
	{
		if (is_null($aggs)) {
			return ['usd' => new \stdClass(), 'data' => []];
		}

		// USD【合计】
		$usd = [
			'amount' => 0,
			'bet_num' => 0,
			'revenue' => 0,
		];

		// 分游戏【合计】
		$data = collect($aggs['group']['buckets'])->map(function ($item)use(&$usd) {

			$org = Org::where('code', $item['key']['plat_code'])->with([
				'config' => function($query){
					$query->select(['plat_code', 'rate']);
				}
			])->select('*')->first();

			$rate = empty($org) ? 0 : $org->config->rate;

			$result = [
				'plat_code' => $item['key']['plat_code'],
				'rate' => $rate,
				'rates' => [$rate],
				'org' => [
					'code' => $item['key']['plat_code'],
					'name' => !empty($org) ? $org->name : '',
				],
				'bet_num' => $item['usd_bet_num']['value'],
				'amount' => -$item['usd_gain_player']['value'],
				// 'rates' => [$rate],
				'revenue' => $this->makeRound((-$item['usd_gain_player']['value']) * $rate),
			];

			$usd['amount'] += $result['amount'];
			$usd['bet_num'] += $result['bet_num'];
			$usd['revenue'] += $result['revenue'];

			return $result;
		});

		return [
			'usd' => $usd,
			'data' => $data,
		];
	}

	private function makeStats($aggs, $request)
	{
		if (is_null($aggs)) {
			return ['usd' => new \stdClass(), 'currency' => []];
		}

		// USD【合计】
		$usd = [
			'amount' => 0,
			'bet_num' => 0,
			'revenue' => 0,
		];

		// 分币种【合计】
		$currency = [];

		collect($aggs['group']['buckets'])->map(function ($item)use(&$usd, &$currency, $request) {

			$grouopArr = explode('_', rtrim($item['key']['group_str'], '_'));
			if(!isset($currency[$grouopArr[0]])){
				$currency[$grouopArr[0]] = [
					'amount' => 0,
					'bet_num' => 0,
					'currency' => $grouopArr[0],
					'revenue' => 0,
				];
			}

			$org = Org\Config::where('plat_code', $grouopArr[1])->first();
			$rate = empty($org) ? 0 : $org->rate;

			$currency[$grouopArr[0]]['amount'] += -$item['gain_player']['value'];
			$currency[$grouopArr[0]]['bet_num'] += $item['bet_num']['value'];
			$currency[$grouopArr[0]]['revenue'] += $this->makeRound((-$item['gain_player']['value']) * $rate);


			$usd['amount'] += -$item['usd.gain_player']['value'];
			$usd['bet_num'] += $item['usd.bet_num']['value'];
			$usd['revenue'] += $this->makeRound((-$item['usd.gain_player']['value']) * $rate);
		});

		return [
			'stat' => [
				'usd' => $usd,
				'sts' => array_values($currency),
			],
		];
	}

	private function getData($aggs, $request, $group_by='day')
	{
		if (is_null($aggs)) {
			return ['data' => []];
		}

		$data = collect($aggs['group']['buckets'])->map(function ($item)use(&$usd, &$currency, $request, $group_by) {

			$grouopArr = explode('_', rtrim($item['key']['group_str'], '_'));

			$org = Org\Config::where('plat_code', $grouopArr[1])->first();
			$rate = empty($org) ? 0 : $org->rate;

			return [
				'amount' => -$item['gain_player']['value'],
				'bet_num' => $item['bet_num']['value'],
				'currency' => $grouopArr[0],
				'group_by' => $group_by,
				'plat_code' => $grouopArr[1],
				'time_zone' => Timed::getTimezoneName(),
				'timed' => $item['key']['timed'],
				'usd'=>
					[
						'amount' => -$item['usd.gain_player']['value'],
						'bet_num' => $item['usd.bet_num']['value'],
					],
			];
		});

		//查询org
		$plat_codes = array_column($data->toArray(), 'plat_code');
		$orgs = Org::whereIn('code', $plat_codes)->with([
			'config' => function($query){
				$query->select(['plat_code', 'rate']);
			}
		])->select(['code', 'name'])->get()->toArray();
		$orgArr = array_column($orgs, null, 'code');

		$data->transform(function ($item)use($orgArr) {
			$rate = isset($orgArr[$item['plat_code']]) && !empty($orgArr[$item['plat_code']]['config']['rate']) ? $orgArr[$item['plat_code']]['config']['rate'] : 0;

			$item['usd']['revenue'] = $this->makeRound(($item['usd']['amount']) * $rate);
			return $item + [
					'rate' => $rate,
					'rates' => [$rate],
					'revenue' => $this->makeRound(($item['amount']) * $rate),
					'org' =>[
						'code' => $item['plat_code'],
						'name' => isset($orgArr[$item['plat_code']]) ? $orgArr[$item['plat_code']]['name'] : $item['plat_code'],
					]
				];
		});

		return [
			'data' => $data,
		];
	}
}
